<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>服务降级与熔断测试</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
    <style>
        body {
            padding: 20px;
            background-color: #f8f9fa;
        }
        .container {
            max-width: 1000px;
            margin: 0 auto;
            background-color: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 0 15px rgba(0,0,0,0.1);
        }
        .server-box {
            padding: 20px;
            margin-bottom: 20px;
            border-radius: 8px;
            text-align: center;
        }
        .current-server {
            background-color: #e7f5ff;
            border: 2px solid #4dabf7;
        }
        .target-server {
            background-color: #fff9db;
            border: 2px solid #ffd43b;
        }
        .port-badge {
            font-size: 24px;
            padding: 5px 15px;
        }
        .port-normal {
            background-color: #4dabf7;
        }
        .port-fallback {
            background-color: #ff6b6b;
        }
        .control-panel {
            margin: 30px 0;
            padding: 20px;
            background-color: #f1f3f5;
            border-radius: 8px;
        }
        .result-panel {
            margin-top: 30px;
            min-height: 300px;
        }
        .call-history {
            max-height: 300px;
            overflow-y: auto;
        }
        .history-item {
            padding: 10px;
            margin-bottom: 5px;
            border-radius: 5px;
        }
        #autoRefreshProgress {
            height: 5px;
        }
        #statistics {
            margin-top: 20px;
        }
        .circuit-state {
            font-size: 18px;
            font-weight: bold;
            padding: 10px;
            border-radius: 5px;
            text-align: center;
        }
        .state-closed {
            background-color: #8ce99a;
            color: #2b8a3e;
        }
        .state-open {
            background-color: #ffc9c9;
            color: #c92a2a;
        }
        .state-half-open {
            background-color: #ffec99;
            color: #e67700;
        }
        .state-disabled {
            background-color: #dee2e6;
            color: #495057;
        }
        .state-forced-open {
            background-color: #c5f6fa;
            color: #0b7285;
        }
        .metrics-panel {
            background-color: #f8f9fa;
            padding: 15px;
            border-radius: 8px;
            margin-top: 15px;
        }
        .metric-item {
            margin-bottom: 10px;
        }
        .metric-label {
            font-weight: bold;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1 class="text-center mb-4">服务降级与熔断测试面板</h1>
        
        <div class="row">
            <div class="col-md-6">
                <div class="server-box current-server">
                    <h3>当前服务实例</h3>
                    <span class="badge port-badge port-normal" th:text="${currentPort}"></span>
                    <p class="mt-2">您正在访问的服务实例端口</p>
                </div>
            </div>
            <div class="col-md-6">
                <div class="server-box target-server">
                    <h3>目标服务实例</h3>
                    <span class="badge port-badge port-normal" id="targetPort">等待调用...</span>
                    <p class="mt-2">服务调用的目标实例端口</p>
                </div>
            </div>
        </div>
        
        <div class="control-panel">
            <h3>控制面板</h3>
            <div class="row mb-3">
                <div class="col-md-6">
                    <button id="callOnceBtn" class="btn btn-primary w-100">单次调用服务</button>
                </div>
                <div class="col-md-6">
                    <button id="autoRefreshBtn" class="btn btn-success w-100">自动调用 (3秒)</button>
                </div>
            </div>
            <div class="progress mb-3">
                <div id="autoRefreshProgress" class="progress-bar" role="progressbar" style="width: 0%"></div>
            </div>
            <div class="row">
                <div class="col-md-6">
                    <button id="toggleServiceBtn" class="btn btn-warning w-100">切换服务可用状态</button>
                </div>
                <div class="col-md-6">
                    <button id="resetStatsBtn" class="btn btn-danger w-100">重置统计信息</button>
                </div>
            </div>
        </div>
        
        <div class="row">
            <div class="col-md-6">
                <div class="card">
                    <div class="card-header">
                        <h3>熔断器状态</h3>
                    </div>
                    <div class="card-body">
                        <div id="circuitState" class="circuit-state state-closed">
                            CLOSED (关闭)
                        </div>
                        <div class="metrics-panel">
                            <h5>熔断器指标</h5>
                            <div class="metric-item">
                                <span class="metric-label">失败率:</span>
                                <span id="failureRate">0%</span>
                            </div>
                            <div class="metric-item">
                                <span class="metric-label">慢调用率:</span>
                                <span id="slowCallRate">0%</span>
                            </div>
                            <div class="metric-item">
                                <span class="metric-label">缓冲调用数:</span>
                                <span id="bufferedCalls">0</span>
                            </div>
                            <div class="metric-item">
                                <span class="metric-label">失败调用数:</span>
                                <span id="failedCalls">0</span>
                            </div>
                            <div class="metric-item">
                                <span class="metric-label">慢调用数:</span>
                                <span id="slowCalls">0</span>
                            </div>
                            <div class="metric-item">
                                <span class="metric-label">成功调用数:</span>
                                <span id="successfulCalls">0</span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <div class="col-md-6">
                <div class="card">
                    <div class="card-header">
                        <h3>服务状态</h3>
                    </div>
                    <div class="card-body">
                        <div class="alert" id="serviceStatus">
                            服务状态: 等待检测...
                        </div>
                        <div id="statistics">
                            <h5>统计信息</h5>
                            <div class="row">
                                <div class="col-6">
                                    <div class="card">
                                        <div class="card-body text-center">
                                            <h3 id="totalCallsCount">0</h3>
                                            <p>总调用次数</p>
                                        </div>
                                    </div>
                                </div>
                                <div class="col-6">
                                    <div class="card">
                                        <div class="card-body text-center">
                                            <h3 id="successCallsCount">0</h3>
                                            <p>成功调用次数</p>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="row mt-3">
                                <div class="col-6">
                                    <div class="card">
                                        <div class="card-body text-center">
                                            <h3 id="failedCallsCount">0</h3>
                                            <p>失败调用次数</p>
                                        </div>
                                    </div>
                                </div>
                                <div class="col-6">
                                    <div class="card">
                                        <div class="card-body text-center">
                                            <h3 id="fallbackCallsCount">0</h3>
                                            <p>降级调用次数</p>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        
        <div class="result-panel">
            <h3>调用历史</h3>
            <div id="callHistory" class="call-history">
                <div class="alert alert-info">点击"单次调用服务"或"自动调用"按钮开始测试</div>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            const callOnceBtn = document.getElementById('callOnceBtn');
            const autoRefreshBtn = document.getElementById('autoRefreshBtn');
            const toggleServiceBtn = document.getElementById('toggleServiceBtn');
            const resetStatsBtn = document.getElementById('resetStatsBtn');
            const targetPort = document.getElementById('targetPort');
            const callHistory = document.getElementById('callHistory');
            const autoRefreshProgress = document.getElementById('autoRefreshProgress');
            const serviceStatus = document.getElementById('serviceStatus');
            
            const circuitState = document.getElementById('circuitState');
            const failureRate = document.getElementById('failureRate');
            const slowCallRate = document.getElementById('slowCallRate');
            const bufferedCalls = document.getElementById('bufferedCalls');
            const failedCalls = document.getElementById('failedCalls');
            const slowCalls = document.getElementById('slowCalls');
            const successfulCalls = document.getElementById('successfulCalls');
            
            const totalCallsCount = document.getElementById('totalCallsCount');
            const successCallsCount = document.getElementById('successCallsCount');
            const failedCallsCount = document.getElementById('failedCallsCount');
            const fallbackCallsCount = document.getElementById('fallbackCallsCount');
            
            let autoRefreshInterval;
            let isAutoRefreshing = false;
            
            // 初始化 - 获取服务状态
            updateServiceStatus();
            
            // 单次调用
            callOnceBtn.addEventListener('click', function() {
                callService();
            });
            
            // 自动调用
            autoRefreshBtn.addEventListener('click', function() {
                if (isAutoRefreshing) {
                    stopAutoRefresh();
                    autoRefreshBtn.textContent = '自动调用 (3秒)';
                    autoRefreshBtn.classList.replace('btn-danger', 'btn-success');
                } else {
                    startAutoRefresh();
                    autoRefreshBtn.textContent = '停止自动调用';
                    autoRefreshBtn.classList.replace('btn-success', 'btn-danger');
                }
            });
            
            // 切换服务状态
            toggleServiceBtn.addEventListener('click', function() {
                toggleService();
            });
            
            // 重置统计信息
            resetStatsBtn.addEventListener('click', function() {
                resetStatistics();
            });
            
            function startAutoRefresh() {
                isAutoRefreshing = true;
                callService();
                
                let progress = 0;
                const progressInterval = setInterval(() => {
                    progress += 1;
                    autoRefreshProgress.style.width = `${progress/30*100}%`;
                    if (progress >= 30) {
                        clearInterval(progressInterval);
                    }
                }, 100);
                
                autoRefreshInterval = setInterval(() => {
                    autoRefreshProgress.style.width = '0%';
                    callService();
                    
                    progress = 0;
                    const newProgressInterval = setInterval(() => {
                        progress += 1;
                        autoRefreshProgress.style.width = `${progress/30*100}%`;
                        if (progress >= 30) {
                            clearInterval(newProgressInterval);
                        }
                    }, 100);
                }, 3000);
            }
            
            function stopAutoRefresh() {
                isAutoRefreshing = false;
                clearInterval(autoRefreshInterval);
                autoRefreshProgress.style.width = '0%';
            }
            
            function callService() {
                fetch('/api/circuit-breaker/call')
                    .then(response => response.json())
                    .then(data => {
                        const targetPortValue = data.port;
                        targetPort.textContent = targetPortValue;
                        
                        if (targetPortValue === '降级服务') {
                            targetPort.className = 'badge port-badge port-fallback';
                        } else {
                            targetPort.className = 'badge port-badge port-normal';
                        }
                        
                        // 更新历史记录
                        const historyItem = document.createElement('div');
                        historyItem.className = `history-item bg-light`;
                        const timestamp = new Date().toLocaleTimeString();
                        
                        if (targetPortValue === '降级服务') {
                            historyItem.innerHTML = `
                                <strong>${timestamp}</strong>: 
                                从端口 <span class="badge bg-primary">${data.sourcePort}</span> 
                                调用失败，启用降级服务 <span class="badge bg-danger">降级</span>
                                <small>${data.message || ''}</small>
                            `;
                        } else {
                            historyItem.innerHTML = `
                                <strong>${timestamp}</strong>: 
                                从端口 <span class="badge bg-primary">${data.sourcePort}</span> 
                                调用到端口 <span class="badge bg-success">${targetPortValue}</span>
                            `;
                        }
                        
                        callHistory.insertBefore(historyItem, callHistory.firstChild);
                        
                        // 更新统计信息
                        updateServiceStatus();
                    })
                    .catch(error => {
                        console.error('Error:', error);
                        const historyItem = document.createElement('div');
                        historyItem.className = 'history-item alert alert-danger';
                        historyItem.textContent = `调用失败: ${error.message}`;
                        callHistory.insertBefore(historyItem, callHistory.firstChild);
                        
                        if (isAutoRefreshing) {
                            stopAutoRefresh();
                            autoRefreshBtn.textContent = '自动调用 (3秒)';
                            autoRefreshBtn.classList.replace('btn-danger', 'btn-success');
                        }
                    });
            }
            
            function toggleService() {
                fetch('/api/circuit-breaker/toggle')
                    .then(response => response.json())
                    .then(data => {
                        updateServiceStatus();
                        
                        const historyItem = document.createElement('div');
                        historyItem.className = 'history-item alert alert-warning';
                        historyItem.textContent = `服务状态已切换: ${data.message}`;
                        callHistory.insertBefore(historyItem, callHistory.firstChild);
                    })
                    .catch(error => {
                        console.error('Error:', error);
                    });
            }
            
            function resetStatistics() {
                fetch('/api/circuit-breaker/reset')
                    .then(response => response.json())
                    .then(data => {
                        updateServiceStatus();
                        
                        const historyItem = document.createElement('div');
                        historyItem.className = 'history-item alert alert-info';
                        historyItem.textContent = `统计信息已重置`;
                        callHistory.insertBefore(historyItem, callHistory.firstChild);
                    })
                    .catch(error => {
                        console.error('Error:', error);
                    });
            }
            
            function updateServiceStatus() {
                fetch('/api/circuit-breaker/stats')
                    .then(response => response.json())
                    .then(data => {
                        // 更新服务状态
                        const available = data.serviceAvailable;
                        serviceStatus.className = available ? 'alert alert-success' : 'alert alert-danger';
                        serviceStatus.textContent = available ? '服务状态: 可用' : '服务状态: 不可用';
                        
                        // 更新统计数据
                        totalCallsCount.textContent = data.totalCalls;
                        successCallsCount.textContent = data.successCalls;
                        failedCallsCount.textContent = data.failedCalls;
                        fallbackCallsCount.textContent = data.fallbackCalls;
                        
                        // 更新熔断器状态
                        const cbStatus = data.circuitBreakerStatus;
                        if (cbStatus) {
                            updateCircuitBreakerStatus(cbStatus);
                        }
                    })
                    .catch(error => {
                        console.error('Error:', error);
                    });
            }
            
            function updateCircuitBreakerStatus(status) {
                // 更新熔断器状态
                const state = status.state;
                circuitState.className = 'circuit-state';
                
                switch (state) {
                    case 'CLOSED':
                        circuitState.classList.add('state-closed');
                        circuitState.textContent = 'CLOSED (关闭)';
                        break;
                    case 'OPEN':
                        circuitState.classList.add('state-open');
                        circuitState.textContent = 'OPEN (开启)';
                        break;
                    case 'HALF_OPEN':
                        circuitState.classList.add('state-half-open');
                        circuitState.textContent = 'HALF_OPEN (半开)';
                        break;
                    case 'DISABLED':
                        circuitState.classList.add('state-disabled');
                        circuitState.textContent = 'DISABLED (禁用)';
                        break;
                    case 'FORCED_OPEN':
                        circuitState.classList.add('state-forced-open');
                        circuitState.textContent = 'FORCED_OPEN (强制开启)';
                        break;
                    default:
                        circuitState.classList.add('state-closed');
                        circuitState.textContent = state;
                }
                
                // 更新指标
                failureRate.textContent = status.failureRate + '%';
                slowCallRate.textContent = status.slowCallRate + '%';
                bufferedCalls.textContent = status.numberOfBufferedCalls;
                failedCalls.textContent = status.numberOfFailedCalls;
                slowCalls.textContent = status.numberOfSlowCalls;
                successfulCalls.textContent = status.numberOfSuccessfulCalls;
            }
        });
    </script>
</body>
</html> 